import Vue from 'vue'
import axios from 'axios'
import {
  baseURL,
  contentType,
  invalidCode,
  noPermissionCode,
  requestTimeout,
  successCode,
  tokenName,
  loginInterception,
  recordRoute
} from '@/config'
import store from '@/store'
import qs from 'qs'
import router from '@/router'
import {
  isArray
} from '@/utils/validate'
import {
  Loading,
  MessageBox
} from 'element-ui';

const handleCode = (code, msg) => {
  switch (code) {
    case invalidCode:
      Vue.prototype.$baseAlert(
        '您的登录状态已经失效，请重新登录!',
        null,
        async () => {
          store.dispatch('user/resetAccessToken').catch(() => {})
          if (loginInterception) {
            location.reload()
          }
        }
      )
      break
    case noPermissionCode:
      MessageBox.alert('暂无权限,请重新登录', '提示', {
        confirmButtonText: '确定',
        callback: async action => {
          await store.dispatch('user/logout')
          if (recordRoute) {
            const fullPath = router.fullPath
            router.push(`/login?redirect=${fullPath}`)
          } else {
            router.push('/login')
          }
        }
      });
      break
    default:
      Vue.prototype.$baseMessage(msg || `后端接口${code}异常`, 'error')
      break
  }
}

const instance = axios.create({
  baseURL,
  timeout: requestTimeout,
  headers: {
    'Content-Type': contentType,
  },
})

//loading对象
let loading;

//当前正在请求的数量
let needLoadingRequestCount = 0;

//显示loading加载中
function showLoading(target) {
  // 后面这个判断很重要，因为关闭时加了抖动，此时loading对象可能还存在，
  // 但needLoadingRequestCount已经变成0.避免这种情况下会重新创建个loading
  if (needLoadingRequestCount === 0 && !loading) {
    loading = Loading.service({
      lock: true,
      text: "数据加载中，请稍后...",
      background: 'rgba(255, 255, 255, 0.95)',
      target: target || ".more-container",
    });
  }
  needLoadingRequestCount++;
}

//隐藏loading
function hideLoading() {
  needLoadingRequestCount--;
  needLoadingRequestCount = Math.max(needLoadingRequestCount, 0); //做个保护
  if (needLoadingRequestCount === 0) {
    //关闭loading
    toHideLoading();
  }
}

//防抖：将 300ms 间隔内的关闭 loading 便合并为一次。防止连续请求时， loading闪烁的问题。
var toHideLoading = _.debounce(() => {
  Vue.prototype.$nextTick(() => { // 以服务的方式调用的 Loading 需要异步关闭
    loading.close();
    loading = null
  });
}, 300);

instance.interceptors.request.use(
  (config) => {
    if (store.getters['user/accessToken']) {
      //请求头添加token名字
      config.headers[tokenName] = store.getters['user/accessToken']
    }
    if (config.data && config.headers['Content-Type'] === 'application/x-www-form-urlencoded;charset=UTF-8') {
      config.data = qs.stringify(config.data)
    }
    //判断当前请求是否设置了不显示Loading
    if (config.headers.showLoading !== false) {
      showLoading(config.headers.loadingTarget);
    }
    return config
  },
  (error) => {
    //判断当前请求是否设置了不显示Loading
    if (config.headers.showLoading !== false) {
      hideLoading();
    }
    return Promise.reject(error)
  }
)

instance.interceptors.response.use(
  (response) => {
    const {
      data,
      config
    } = response
    const {
      code,
      msg
    } = data
    // 操作正常Code数组
    const codeVerificationArray = isArray(successCode) ?
      [...successCode] :
      [...[successCode]];
    //判断当前请求是否设置了不显示Loading（不显示自然无需隐藏）
    if (response.config.headers.showLoading !== false) {
      hideLoading();
    }
    // 是否操作正常
    if (codeVerificationArray.includes(code)) {
      return data
    } else {
      handleCode(code, msg)
      return data
    }
  },
  (error) => {
    hideLoading();
    const {
      response,
      message
    } = error
    if (error.response && error.response.data) {
      const {
        status,
        data
      } = response
      handleCode(status, data.msg || message)
      return Promise.reject(error)
    } else {
      let {
        message
      } = error
      if (message === 'Network Error') {
        message = '数据接口服务连接异常'
      }
      if (message.includes('timeout')) {
        message = '数据接口服务连接异常'
      }
      if (message.includes('Request failed with status code')) {
        const code = message.substr(message.length - 3)
        message = '后端接口' + code + '异常'
      }
      Vue.prototype.$baseMessage(message || `后端接口未知异常`, 'error')

      return Promise.reject(error)
    }
  }
)

export default instance
